/*!	 synfig/rendering/renderer.h
**	 Renderer Header
**
**	......... ... 2015 Ivan Mahonin
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifndef __SYNFIG_RENDERING_RENDERER_H
#define __SYNFIG_RENDERING_RENDERER_H

#include <cstdio>

#include <map>

#include "optimizer.h"

namespace synfig
{
namespace rendering
{

class RenderQueue;

class Renderer: public etl::shared_object
{
public:
    typedef etl::handle<Renderer> Handle;

    struct DebugOptions {
        String task_list_log;
        String task_list_optimized_log;
        String result_image;
    };

private:
    static Handle blank;
    static std::map<String, Handle> *renderers;
    static RenderQueue *queue;
    static DebugOptions debug_options;
    static long long last_registered_optimizer_index;

    Optimizer::List optimizers[Optimizer::CATEGORY_ID_COUNT];

public:

    virtual ~Renderer();

    virtual String get_name() const = 0;

    const Optimizer::List& get_optimizers(Optimizer::CategoryId category_id) const
    {
        return optimizers[category_id];
    }
    bool is_optimizer_registered(const Optimizer::Handle &optimizer) const;
    void register_optimizer(Real order, const Optimizer::Handle &optimizer);
    void register_optimizer(const Optimizer::Handle &optimizer);
    void unregister_optimizer(const Optimizer::Handle &optimizer);

private:
    void optimize_recursive(
        const Optimizer::List &optimizers,
        const Optimizer::RunParams& params,
        int &calls_count,
        int &optimizations_count,
        int max_level) const;

    void log(
        const String &logfile,
        const Task::Handle &task,
        const Optimizer::RunParams* optimization_stack = NULL,
        int level = 0) const;
    void log(
        const String &logfile,
        const Task::List &list,
        const String &name = String(),
        const Optimizer::RunParams* optimization_stack = NULL) const;

    static void initialize_renderers();
    static void deinitialize_renderers();

    typedef std::pair<Surface::Handle, int>             DepTargetKey;
    typedef std::pair<Task::Handle, Task::Set>          DepTargetValue;
    typedef std::multimap<DepTargetKey, DepTargetValue> DepTargetMap;
    typedef DepTargetMap::value_type                    DepTargetPair;

    void find_deps(const Task::List &list) const;

public:
    int get_max_simultaneous_threads() const;
    void optimize(Task::List &list) const;
    bool run(const Task::List &list) const;
    void enqueue(const Task::List &list, const Task::Handle &finish_signal_task = Task::Handle()) const;

    static void initialize();
    static void deinitialize();
    static void register_renderer(const String &name, const Renderer::Handle &renderer);
    static void unregister_renderer(const String &name);
    static const Renderer::Handle& get_renderer(const String &name);
    static const std::map<String, Handle>& get_renderers();

    static const DebugOptions& get_debug_options()
    {
        return debug_options;
    }

    static bool subsys_init()
    {
        initialize();
        return true;
    }

    static bool subsys_stop()
    {
        deinitialize();
        return false;
    }
};

} /* end namespace rendering */
} /* end namespace synfig */

#endif